#include "pf.h"

#include <stdio.h>
#include <iostream>
#include<errno.h>
using namespace std;

PF_Manager* PF_Manager::_pf_manager = 0;


PF_Manager* PF_Manager::Instance()
{
    if(!_pf_manager)
        _pf_manager = new PF_Manager();
    
    return _pf_manager;    
}


PF_Manager::PF_Manager()
{
}


PF_Manager::~PF_Manager()
{
	delete _pf_manager;
}

    
RC PF_Manager::CreateFile(const char *fileName)
{
	FILE *file;

	if((file=fopen(fileName,"r"))==NULL)// if file doesn't exist already
	{
		file=fopen(fileName,"wb+"); //create an empty file for both reading and writing
		if(file!=NULL)
		{
			//cout<<"file "<<fileName<<" created successfully"<<endl;
			fclose(file);
			return 0;
		}
		else
		{
			//cout<<"Error: Could not create the file"<<endl;
			return 1;
		}
	}
	fclose(file);
	//cout<<"File you trying to create already exists"<<endl;
    return -1;
}


RC PF_Manager::DestroyFile(const char *fileName)
{

	FILE *file;
	//if((file=fopen(fileName,"rb+")))
	{
		//fclose(file);
		//cout<<"\nfileName"<<fileName<<endl;
		if(remove(fileName)!=0)
		{
			//cout<<"Error removing the file "<<fileName<<endl;
			//cout<<"\nerrno="<<errno<<endl;
			return -1;
		}
		else
		{
			//cout<<"File "<<fileName<<" deleted successfully"<<endl;
			return 0;
		}

	}
	//cout<<"File "<<fileName<<" doesn't exist!!!"<<endl;
    return -1;
}


RC PF_Manager::OpenFile(const char *fileName, PF_FileHandle &fileHandle)
{
	FILE *file;
	file=fopen(fileName,"rb+");

	if(file!=NULL)
	{
		//cout<<"File "<<fileName<<" opened"<<endl;
		fileHandle.localFilePtr=file;
		return 0;
	}
	//cout<<"File "<<fileName<<" couldn't be opened"<<endl;
    return -1;
}


RC PF_Manager::CloseFile(PF_FileHandle &fileHandle)
{
	fflush(fileHandle.localFilePtr);
	if(fclose(fileHandle.localFilePtr)==0)
		return 0;
    return -1;
}


PF_FileHandle::PF_FileHandle()
{
}
 

PF_FileHandle::~PF_FileHandle()
{

}


RC PF_FileHandle::ReadPage(PageNum pageNum, void *data)
{
	int totalPages=GetNumberOfPages();


	if(pageNum>totalPages-1)
	{
		//cout<<"Page does not exist"<<endl;
		return -1;
	}
	else
	{
		int position=pageNum*PF_PAGE_SIZE; //assuming page numbers start with 0
		if(fseek(this->localFilePtr,position,SEEK_SET)!=0)
		{
			//cout<<"can't reposition the seek pointer"<<endl;
			//rewind(this->localFilePtr);
			return -1;
		}
		else
		{
			int bytesRead=fread(data,1,4096,this->localFilePtr);
			if(bytesRead!=4096)
			{
				//cout<<"Couldn't read the entire page"<<endl;
				//rewind(this->localFilePtr);
				return -1;
			}
			//rewind(this->localFilePtr);
			return 0;
		}
	}
    return -1;
}


RC PF_FileHandle::WritePage(PageNum pageNum, const void *data)
{
	int totalPages=GetNumberOfPages();

		if(pageNum>totalPages-1)
		{
			//cout<<"Page does not exist"<<endl;
			return -1;
		}
		else
		{
			//cout<<"page exists";
			int position=pageNum*PF_PAGE_SIZE; //assuming page numbers start with 0
			if(fseek(this->localFilePtr,position,SEEK_SET)!=0)
			{
				//cout<<"can't reposition the seek pointer"<<endl;
				//rewind(this->localFilePtr);
				return -1;
			}
			else
			{
				int bytesWritten=fwrite(data,1,4096,this->localFilePtr);
				if(bytesWritten!=4096)
				{
					//cout<<"Couldn't write the entire page"<<endl;
					//rewind(this->localFilePtr);
					return -1;
				}
				//cout<<"page written successfully";
				//rewind(this->localFilePtr);
				return 0;
			}
		}
	    return -1;
}

RC PF_FileHandle::AppendPage(const void *data)
{
	int totalPages=GetNumberOfPages();
	int position=totalPages*PF_PAGE_SIZE; //assuming page numbers start with 0
	if(fseek(this->localFilePtr,position,SEEK_SET)!=0)
	{
		//cout<<"can't reposition the seek pointer"<<endl;
		//rewind(this->localFilePtr);
		return -1;
	}
	else
	{
		int bytesWritten=fwrite(data,1,4096,this->localFilePtr);
		if(bytesWritten!=4096)
		{
			//cout<<"Couldn't write the entire page"<<endl;
			//rewind(this->localFilePtr);
			return -1;
		}
		//rewind(this->localFilePtr);
		return 0;
	}
    return -1;
}


unsigned PF_FileHandle::GetNumberOfPages()
{

	fseek(this->localFilePtr,0,SEEK_END);
	int filesize=ftell(this->localFilePtr);
	unsigned int numOfPages=(filesize/PF_PAGE_SIZE);
	if(filesize%PF_PAGE_SIZE!=0)
		numOfPages++;
	//rewind(this->localFilePtr);
    return numOfPages;
}


